Predictive Modelling – NMC Conditions
Nowcasting and short-term forecasts for notifiable conditions using EpiNow2
Overview
This section showcases nowcasting and short-term outbreak forecasting for key notifiable medical conditions (NMC) reported through the national surveillance system. The models use the EpiNow2 R package, which combines:
- Nowcasting – adjusting for reporting delays
- Estimation of \(R_t\) – the time-varying effective reproduction number
- Short-term forecasting – projecting cases up to 3 weeks ahead
| NMC Category | Conditions |
|---|---|
| Vaccine-preventable | Fever-Rash (Measles + Rubella), Pertussis, Diphtheria, Tetanus, Hepatitis B, Haemophilus influenzae type B, Congenital rubella syndrome, Poliomyelitis / AFP, Yellow fever |
| Category 1 — Immediate notification (non-VPD) | Cholera, Malaria, Covid-19, Enteric fever, Meningococcal disease, Listeriosis, Mpox |
| Category 2 — Routine notification | Hepatitis A |
Forecasts are only generated for conditions with ≥ 60 days of data.
20 February 2026 23:54 — Horizon: 28 days — Conditions: Acute flaccid paralysis, Cholera, Congenital rubella syndrome, Covid-19, Diphtheria, Enteric fever (typhoid or paratyphoid fever), Haemophilus influenzae type B, Hepatitis A, Hepatitis B, Listeriosis, Malaria, Fever-Rash, Meningococcal disease, Mpox, Pertussis, Poliomyelitis, Tetanus, Yellow fever
Surveillance Epicurves
An epidemic curve of reported cases for each forecasted NMC condition, aggregated weekly at the national level.
EpiNow2 Forecasts
Each panel shows the median estimate (solid line), 50 % credible interval (dark ribbon) and 90 % credible interval (light ribbon), all smoothed with a 7-day rolling average to remove weekend reporting artefacts. The shaded forecast horizon extends 28 days (4 weeks) beyond the last data point.
Standard EpiNow2 Diagnostic Plots
The panels below show the native EpiNow2 diagnostic output for each condition. Each plot combines three key elements in a single view:
- Reported cases — observed data with nowcast / forecast and credible intervals
- Estimated infections — latent infection trajectory inferred by the model
- Effective reproduction number (\(R_t\)) — with threshold line at \(R_t = 1\)
These are produced directly by EpiNow2::plot() and provide a comprehensive snapshot of the epidemic state without any post-processing.


















Animated Forecast Outlook
The rolling forecast shows how the predicted trajectory shifted each week as new data arrived. Each coloured line represents a forecast made on a different snapshot date; vertical markers show where each snapshot’s data ended.
This visualisation helps assess:
- Forecast stability – are successive predictions consistent?
- Outbreak acceleration – are newer forecasts trending higher?
- Early warning – divergence between snapshots signals emerging outbreaks.
Interpretation Guide
Element | What it means | Suggested action |
|---|---|---|
Median line | Most likely trajectory based on current Rt | Monitor closely; compare to previous snapshots |
50% CI (dark ribbon) | Central range – 1 in 2 chance the true value falls here | Normal operational uncertainty |
90% CI (light ribbon) | Wide range – 9 in 10 chance the true value falls here | If real counts approach the upper bound → escalate |
Forecast horizon (dashed red) | Where observed data ends and prediction begins | Predictions degrade further from this line |
Rolling snapshots diverging upward | Successive forecasts are increasingly pessimistic | Possible outbreak acceleration → trigger response protocols |
Rolling snapshots converging | Outbreak is stabilising or declining | Maintain surveillance; consider de-escalation |
Effective Reproduction Number (\(R_t\))
The time-varying reproduction number \(R_t\) indicates how many secondary cases each infected person generates on average.
- \(R_t > 1\) → epidemic is growing
- \(R_t = 1\) → epidemic is stable
- \(R_t < 1\) → epidemic is declining
Growth-Rate Summary Table
Condition | Latest Rt | Lower 90% | Upper 90% | Assessment | Date |
|---|---|---|---|---|---|
Acute flaccid paralysis | 1.01 | 0.94 | 1.17 | Growing | 2026-03-19 |
Cholera | 1.02 | 0.79 | 1.28 | Growing | 2026-03-19 |
Congenital rubella syndrome | 0.84 | 0.59 | 1.04 | Declining | 2026-03-19 |
Covid-19 | 0.30 | 0.02 | 1.62 | Declining | 2026-03-19 |
Diphtheria | 0.99 | 0.92 | 1.09 | Stable / slow decline | 2026-03-19 |
Enteric fever (typhoid or paratyphoid fever) | 1.01 | 0.86 | 1.12 | Growing | 2026-03-19 |
Fever-Rash | 0.76 | 0.42 | 1.25 | Declining | 2026-03-19 |
Haemophilus influenzae type B | 1.00 | 0.94 | 1.06 | Stable / slow decline | 2026-03-19 |
Hepatitis A | 0.98 | 0.79 | 1.12 | Stable / slow decline | 2026-03-19 |
Hepatitis B | 0.96 | 0.57 | 1.56 | Stable / slow decline | 2026-03-19 |
Listeriosis | 0.97 | 0.67 | 1.23 | Stable / slow decline | 2026-03-19 |
Malaria | 0.43 | 0.19 | 1.00 | Declining | 2026-03-19 |
Meningococcal disease | 0.99 | 0.91 | 1.06 | Stable / slow decline | 2026-03-19 |
Mpox | 0.85 | 0.43 | 1.10 | Declining | 2026-03-19 |
Pertussis | 0.94 | 0.76 | 1.09 | Stable / slow decline | 2026-03-19 |
Poliomyelitis | 0.69 | 0.13 | 1.43 | Declining | 2026-03-19 |
Tetanus | 0.93 | 0.61 | 1.27 | Stable / slow decline | 2026-03-19 |
Yellow fever | 0.84 | 0.21 | 1.49 | Declining | 2026-03-19 |
Provincial Breakdown
Outbreak Capacity Indicator
A simple traffic-light display combining \(R_t\), recent case trends, and forecast trajectory.
Updating Forecasts
Forecasts are not computed live during dashboard rendering (they take ~5–15 min per condition). Instead, a batch script produces cached .rds files that the dashboard reads.
Prerequisites:
- R ≥ 4.3 with packages:
EpiNow2,data.table,dplyr,lubridate,here,purrr - CmdStan installed (EpiNow2 backend). Install via:
cmdstanr::install_cmdstan() - Aggregated surveillance data in
data/processed/agg_national.rds(produced byR/prepare_dashboard_data.r)
1. Update the surveillance data
# From the project root
cd /Users/briday/Desktop/SAFETP/CLA/NMC_website/NMC_dashboard
Rscript R/prepare_dashboard_data.rThis reads the latest NMC master dataset and produces:
data/processed/agg_national.rdsdata/processed/agg_province.rdsdata/processed/agg_district.rds
2. Run the forecast batch
Rscript R/run_forecasts.rThis produces for each vaccine-preventable condition:
| File | Contents |
|---|---|
forecasts_<condition>.rds |
Single-point EpiNow2 summary (Rt, cases, infections) |
forecasts_obj_<condition>.rds |
Full EpiNow2 result object (for native plot() diagnostics) |
forecasts_rolling_<condition>.rds |
Rolling snapshots for animated outlook |
forecasts_meta.rds |
Run timestamp and parameters |
3. Re-render the dashboard
quarto render by-forecasts/index.qmd
# Or render the full site:
quarto renderConfiguration
Edit the constants at the top of R/run_forecasts.r to adjust:
| Parameter | Default | Description |
|---|---|---|
HORIZON |
28 | Days to forecast ahead (4 weeks) |
LOOKBACK |
360 | Days of history for each model run |
N_REWINDS |
8 | Number of rolling snapshots |
REWIND_STEP |
7 | Days between snapshots |
Adding a new condition
- Ensure the condition appears in
agg_national.rds(viaprepare_dashboard_data.r) - Add disease parameters in
R/epinow2_functions.r→disease_params()function - Add the condition name to
forecast_conditions()in the same file - Re-run
Rscript R/run_forecasts.r
Model Assumptions & Parameters
The table below shows the disease-specific parameters fed into each EpiNow2 forecast. These are defined in R/epinow2_functions.r → disease_params() and sourced from peer-reviewed epidemiological literature. The Reference column cites the primary source for each parameter set — check these when validating or updating assumptions.
Condition | Generation Time | Incubation Period | Rt Prior | Reporting Delay | What This Means | Reference |
|---|---|---|---|---|---|---|
Fever-Rash | Gamma(shape~34, rate~2.9, max=--) | Gamma (see source) | Normal(mean=2.0, sd=1.0) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Fever-Rash to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Lessler et al. (2009) Lancet Infect Dis 9(5):291-300 |
Measles | Gamma(shape~34, rate~2.9, max=--) | Gamma (see source) | Normal(mean=2.0, sd=1.0) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Measles to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Lessler et al. (2009) Lancet Infect Dis 9(5):291-300 |
Rubella | Gamma(shape~27, rate~1.5, max=--) | Gamma (see source) | Normal(mean=2.0, sd=1.0) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Rubella to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Vink et al. (2014) Am J Epidemiol 180(9):865-875; Lessler et al. (2009) |
Pertussis | Gamma(shape~13, rate~0.6, max=--) | Gamma (see source) | Normal(mean=2.0, sd=1.0) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Pertussis to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Vink et al. (2014); Wearing & Rohani (2009) Emerg Infect Dis 15(8):1248 |
Diphtheria | Gamma(shape~7, rate~0.9, max=--) | Gamma (see source) | Normal(mean=2.0, sd=1.0) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Diphtheria to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Truelove et al. (2020) Emerg Infect Dis 26(10):2396; AAP Red Book |
Tetanus | Gamma(shape~8, rate~0.6, max=--) | Gamma (see source) | Normal(mean=1.0, sd=0.5) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Tetanus to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 1 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | WHO Tetanus Position Paper (2017); Roper et al. (2018) Lancet 391:1657 |
Hepatitis B | Gamma(shape~9, rate~0.1, max=--) | Gamma (see source) | Normal(mean=1.5, sd=0.5) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Hepatitis B to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Edmunds et al. (1993) Epidemiol Infect 110(3):569; Liang (2009) Hepatology 49(S5):S13 |
Haemophilus influenzae type B | Gamma(shape~4, rate~1.3, max=--) | Gamma (see source) | Normal(mean=1.5, sd=0.5) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Haemophilus influenzae type B to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Peltola (2000) Clin Microbiol Rev 13(2):302-317; AAP Red Book (2024) |
Congenital rubella syndrome | Gamma(shape~27, rate~1.5, max=--) | Gamma (see source) | Normal(mean=1.5, sd=0.5) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Congenital rubella syndrome to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Vink et al. (2014); Lessler et al. (2009) – rubella parameters |
Poliomyelitis | Gamma(shape~9, rate~0.6, max=--) | Gamma (see source) | Normal(mean=2.0, sd=1.0) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Poliomyelitis to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Fine & Carneiro (1999) Am J Epidemiol 150(12):1332; Nathanson & Kew (2010) Am J Epidemiol 172(11):1213 |
Acute flaccid paralysis | Gamma(shape~9, rate~0.6, max=--) | Gamma (see source) | Normal(mean=2.0, sd=1.0) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Acute flaccid paralysis to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Fine & Carneiro (1999) Am J Epidemiol 150(12):1332; Nathanson & Kew (2010) Am J Epidemiol 172(11):1213 |
Yellow fever | Gamma(shape~16, rate~1.3, max=--) | Gamma (see source) | Normal(mean=1.5, sd=0.5) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Yellow fever to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Johansson et al. (2010) Am J Trop Med Hyg 82(5):930; Monath & Vasconcelos (2015) J Clin Virol 64:160 |
Cholera | Gamma(shape~6, rate~1.2, max=--) | Gamma (see source) | Normal(mean=2.0, sd=1.0) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Cholera to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Azman et al. (2013) J Infect Dis 207(11):1698-1706 |
Malaria | Gamma(shape~14, rate~0.5, max=--) | Gamma (see source) | Normal(mean=1.5, sd=0.5) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Malaria to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Huber et al. (2016) Malar J 15:18; WHO World Malaria Report (2023) |
Covid-19 | Gamma(shape~6, rate~2.0, max=--) | Gamma (see source) | Normal(mean=1.5, sd=0.5) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Covid-19 to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Park et al. (2023) BMC Infect Dis 23:295; Wu et al. (2022) JAMA Netw Open 5(8):e2228008 |
Enteric fever (typhoid or paratyphoid fever) | Gamma(shape~12, rate~0.9, max=--) | Gamma (see source) | Normal(mean=1.5, sd=0.5) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Enteric fever (typhoid or paratyphoid fever) to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Pitzer et al. (2014) PLoS Negl Trop Dis 8(6):e2891; Crump et al. (2015) Clin Microbiol Rev 28(4):901 |
Meningococcal disease | Gamma(shape~8, rate~1.1, max=--) | Gamma (see source) | Normal(mean=1.5, sd=0.5) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Meningococcal disease to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Trotter et al. (2005) Emerg Infect Dis 11(4):563; Rosenstein et al. (2001) NEJM 344(18):1378 |
Listeriosis | Gamma(shape~4, rate~0.2, max=--) | Gamma (see source) | Normal(mean=1.2, sd=0.5) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Listeriosis to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 1 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Goulet et al. (2013) Clin Infect Dis 56(10):1411-1419 |
Mpox | Gamma(shape~8, rate~0.7, max=--) | Gamma (see source) | Normal(mean=1.5, sd=0.5) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Mpox to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Miura et al. (2022) Euro Surveill 27(44):2200806; Thornhill et al. (2022) NEJM 387(8):679 |
Hepatitis A | Gamma(shape~16, rate~0.7, max=--) | Gamma (see source) | Normal(mean=1.5, sd=0.5) | LogNormal(mean=3, sd=2, max=15) | On average, an infected person can spread Hepatitis A to others about several days after being infected themselves. Symptoms typically appear ~several days after exposure. The model starts by assuming each case infects about 2 other people on average, then adjusts this up or down based on the actual reported data. A ~3-day delay is assumed between someone falling ill and the case being officially reported. | Jacobsen & Wiersma (2010) Clin Liver Dis 14(4):591; Lemon et al. (2018) Lancet 391:1587 |
Generation time ≈ serial interval where direct measurement is unavailable. Incubation period = time from exposure to symptom onset. All distributions are Gamma. Reporting delay: default LogNormal(mean=3, sd=2, max=15) when empirical delay data is unavailable. | ||||||
| Parameter | What it controls | Why it matters |
|---|---|---|
| Generation time | Average time between successive infections in a chain (≈ serial interval) | Determines how fast \(R_t\) changes translate into case-count changes |
| Incubation period | Time from infection/exposure to symptom onset | Affects the delay between infection dynamics and observed cases |
| \(R_t\) prior | Starting assumption for reproduction number | Weakly informative — the model quickly learns from data |
| Reporting delay | Time from symptom onset to NMC notification | Accounts for the surveillance lag between illness and official capture |
| What This Means | Plain-language summary of all parameters for this condition | Helps non-technical readers understand what the model assumes |
| Reference | Primary literature source | Used for validation — update if newer estimates become available |
To update parameter values for a condition:
- Open
R/epinow2_functions.r - Find the condition in
disease_params()(search for the condition name in lowercase) - Change
mean,sd,maxvalues to match your preferred literature source - Update the
referencestring to cite the new source - Re-run:
Rscript R/run_forecasts.r - Re-render:
quarto render by-forecasts/index.qmd
Example — changing measles generation time to use a new study:
"fever-rash" = , "measles" = list(
generation_time = EpiNow2::Gamma(mean = 11.0, sd = 2.5, max = 20),
# ↑ changed from 11.7 to 11.0 based on New Study (2026)
incubation_period = EpiNow2::Gamma(mean = 12.5, sd = 2.3, max = 21),
rt_prior = list(mean = 2, sd = 1),
reference = "New Study (2026) Journal Name DOI:..."
),Methods & Technical Details
Model: EpiNow2 v1.8.0 – a Bayesian semi-mechanistic model that jointly estimates the effective reproduction number (\(R_t\)), infection incidence, and reporting patterns. The model is fitted using Hamiltonian Monte Carlo via CmdStan. A day-of-week effect is enabled (obs_opts(week_effect = TRUE)) to account for lower weekend reporting.
Display smoothing: All custom forecast plots apply a 7-day rolling average to both the observed surveillance series and the EpiNow2 median / credible-interval outputs. This removes residual day-of-week jaggedness and highlights the underlying epidemic trend.
Reporting delay: When empirical symptom→notification dates are available in the NMC data, the delay distribution is estimated via EpiNow2::estimate_delay() (capped at 15 days, max 100 observations). Otherwise a default LogNormal(mean=3, sd=2, max=15) prior is used.
Generation time & incubation period: Condition-specific Gamma distributions from published peer-reviewed literature. Key sources: Lessler et al. (2009) for measles/rubella; Vink et al. (2014) for serial intervals; Azman et al. (2013) for cholera; Park et al. (2023) for COVID-19 Omicron estimates. See the parameter table above for full citations. These are fixed inputs — not estimated from the data.
Priors: \(R_t\) priors are weakly informative: Normal(2, 1) for directly-transmitted pathogens, Normal(1.5, 0.5) for vector-borne / lower-Rt conditions. The model quickly learns from data.
Forecast horizon: 28 days (4 weeks) ahead from the last observation date.
History window: 360 days of surveillance data fed to each model run.
Completeness / Timeliness: The NMC is a passive surveillance system; under-reporting varies by condition and province. Forecasts represent reported cases, not true incidence.
Rolling forecast animation: Re-runs the model 8 times (weekly snapshots), each using data up to that snapshot date, to visualise how the forecast outlook evolved over time.